/*
	Copyright (C) 2009 jungil Han <jungil.Han@gmail.com>

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "mkHotkeyButton.h"
#include "../Dialog/mkMainDialog.h"
#include "../Util/mkUtil.h"
#include "../Base/Http/mkHttp.h"
#include "../HttpDownloader/mkHttpDownloader.h"

#include <QPainter>
#include <QMouseEvent>
#include <QFileDialog>
#include <QDirModel>
#include <QApplication>
#include <QUrl>
#include <QTimer>
//#include <QMessageBox>

mkHotkeyButton::mkHotkeyButton( IN QWidget *a_pParent, IN int a_nIndex ) : mkButton ( a_pParent )
{
	setAcceptDrops( true );
	
	m_nIndex = a_nIndex;
	m_nSystemKey = -1;
	m_nNonSystemKey = -1;

	m_strName = "";
	m_strKeyInfo = "";
	m_strFilePath = "";
	m_hotkeyIcon = QIcon();

	/* Set maximum size of mkAnimation attribute, default icon size 32 */
	QSize size( 32 + 8, 32 + 8 );
	SetMaximumAnimationSize( &size );

	connect( this, SIGNAL( SigShowKeyboard( int )), parent()->parent(), SLOT( SlotKeyboardShow( int )));
	connect( this, SIGNAL( clicked() ), this, SLOT( SlotClicked() ));
	
	m_pConfigButton = new mkButton( this );
	m_pConfigButton->SetBGImage( QString( ":/Button/tool_icon_default.png" ), QString( ":/Button/tool_icon_over.png" ), QString( ":/Button/tool_icon_click.png" ));
	m_pConfigButton->setGeometry( 2, 37, 12, 12 );
	m_pConfigButton->setVisible( false );
	connect( m_pConfigButton, SIGNAL( clicked() ), this, SLOT( SlotConfigClicked() ));
	
	m_pDeleteButton = new mkButton ( this );
	m_pDeleteButton->SetBGImage( QString( ":/Button/delete_icon_default.png" ), QString( ":/Button/delete_icon_over.png" ), QString( ":/Button/delete_icon_click.png" ));
	m_pDeleteButton->setGeometry( 56, 37, 12, 12 );
	m_pDeleteButton->setVisible( false );
	connect( m_pDeleteButton, SIGNAL( clicked() ), this, SLOT( SlotDeleteClicked() ));

	m_pPopupMenu = new mkPopupMenu( this );

	m_pHttpFavicon = NULL;

	m_pEnterTimer = new QTimer( this );
	connect( m_pEnterTimer, SIGNAL( timeout() ), this, SLOT( SlotEnterTimer() ));
}

mkHotkeyButton::~mkHotkeyButton()
{
	MK_DELETE( m_pConfigButton );
	MK_DELETE( m_pDeleteButton );
	MK_DELETE( m_pPopupMenu );
	MK_DELETE( m_pHttpFavicon );
	MK_DELETE( m_pEnterTimer );
}

int mkHotkeyButton::GetIndex()
{
	return m_nIndex;
}

QString mkHotkeyButton::GetName()
{
	return m_strName;
}

QString mkHotkeyButton::GetFilePath()
{
	return m_strFilePath;
}

void mkHotkeyButton::SetFilePath( IN QString a_strFilePath )
{
	m_strFilePath = a_strFilePath;
}

void mkHotkeyButton::SetName( IN QString a_strName )
{
	m_strName = a_strName;
}

int mkHotkeyButton::GetHotkeyCode( OUT int *a_pSystemKey, OUT int *a_pNonSystemKey )
{
	if ( !a_pSystemKey || !a_pNonSystemKey )
		return -1;
	
	*a_pSystemKey = m_nSystemKey;
	*a_pNonSystemKey = m_nNonSystemKey;

	return 0;
}

int mkHotkeyButton::LoadHotkey( IN mkHotkeyInfo *a_pHotkeyInfo )
{
	if ( a_pHotkeyInfo->strFileName.contains( "http" )) {
		m_strName = "Loading...";
		m_hotkeyIcon = QIcon();
		m_strFilePath = a_pHotkeyInfo->strFileName;

		/* Download favicon */
		MK_DELETE( m_pHttpFavicon );
		m_pHttpFavicon = new mkHttpDownloader( this );
		m_pHttpFavicon->SetUrl( a_pHotkeyInfo->strFileName );
		m_pHttpFavicon->Connect();
	} else {
		m_strName = GetIconName( a_pHotkeyInfo->strFileName );
		m_hotkeyIcon = GetIcon( a_pHotkeyInfo->strFileName );
		m_strFilePath = a_pHotkeyInfo->strFileName;

		setToolTip( m_strName );
	}

	RegisterHotkey( a_pHotkeyInfo->nSystemKey, a_pHotkeyInfo->nNonSystemKey );
	EnableIcon( true );

	setToolTip( m_strName );
	update();

	return 0;
}

int mkHotkeyButton::RegisterHotkey( IN int a_nSystemKey, IN int a_nNonSystemKey )
{
	m_nSystemKey = a_nSystemKey;
	m_nNonSystemKey = a_nNonSystemKey;

	QString strSystemKey, strNonSystemKey;
	mkUtil::TranslateKeyEnumToText( m_nSystemKey, m_nNonSystemKey, &strSystemKey, &strNonSystemKey );
	m_strKeyInfo = strSystemKey + " + " + strNonSystemKey;

	bool bIsHotkeyEnable = static_cast<mkMainDialog *>( parent()->parent() )->IsEnableHotkey();
	if ( bIsHotkeyEnable )
		mkHotkeyManager::Instance()->RegisterHotkeyAt( m_nIndex );

	return 0;
}

int mkHotkeyButton::EnableIcon( bool a_bIsEnable )
{
	if ( m_hotkeyIcon.isNull() )
		return -1;

	QImage defaultImage, overImage, clickImage;

	if ( a_bIsEnable ) {
		defaultImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Normal ).toImage();
		overImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Active ).toImage();
		clickImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Selected ).toImage();
	} else {
		defaultImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Disabled ).toImage();
		overImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Disabled ).toImage();
		clickImage = m_hotkeyIcon.pixmap( QSize( 32, 32 ), QIcon::Disabled ).toImage();		
	}

	QRect rcFGRect( 19, 14, 32, 32 );
	SetFGImage( defaultImage , overImage, clickImage, &rcFGRect);
	SetAnimation( true );

	return 0;
}

QPixmap mkHotkeyButton::GetIcon( IN QString a_strFile )
{
	QFileInfo fileInfo( a_strFile );
	QFileIconProvider fileIconProvider;
	QIcon appIcon = fileIconProvider.icon( fileInfo );
	QPixmap pixmap = appIcon.pixmap( QSize( 32, 32 ));

	return pixmap;
}

void mkHotkeyButton::OnDownloadedFavicon( IN QString &a_refFaviconFile, IN QString &a_refTitle, IN QString &a_refUrl )
{
	if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() ))
		SlotDeleteClicked();

	QPixmap browserPixmap = GetIcon( mkUtil::GetDefaultBrowser() );
	if ( !a_refFaviconFile.isEmpty() && QFile::exists( a_refFaviconFile ));
		CompositeFavicon( browserPixmap, a_refFaviconFile );

	m_strName = a_refTitle;
	m_strFilePath = a_refUrl;
	m_hotkeyIcon = browserPixmap;

	setToolTip( m_strName );

	if ( m_strKeyInfo.isEmpty() ) {
		EnableIcon( false );
	} else {
		EnableIcon( true );
	}

	update();
}

void mkHotkeyButton::CompositeFavicon( IN QPixmap &a_refTarget, IN QString &a_refFaviconFile )
{
	QPainter painter( &a_refTarget );

	QPixmap faviconPixmap( a_refFaviconFile );
	if ( faviconPixmap.isNull() ) {
		faviconPixmap = GetIcon( a_refFaviconFile );
		painter.drawPixmap( QRect(20, 16, 14, 14), faviconPixmap.scaled( 14, 14, Qt::KeepAspectRatio, Qt::SmoothTransformation ));
	} else {

		painter.fillRect( QRect( 20, 19, 12, 12 ), QColor( 150, 150, 150 ));
		painter.drawPixmap( QRect( 21, 20, 10, 10 ), faviconPixmap.scaled( 10, 10, Qt::KeepAspectRatio, Qt::SmoothTransformation ));
	}

	QFile::remove( a_refFaviconFile );
}

QString mkHotkeyButton::GetIconName( IN QString a_strFile )
{
	QFileInfo fileInfo( a_strFile );
	return fileInfo.completeBaseName();
}

void mkHotkeyButton::mousePressEvent( IN QMouseEvent *a_pEvent )
{
	if ( a_pEvent->button() == Qt::RightButton ) {
		if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() )) {
			m_pPopupMenu->SetVisibleAction( eConfig, true );
			m_pPopupMenu->SetVisibleAction( eDelete, true );
		} else {
			m_pPopupMenu->SetVisibleAction( eConfig, false );
			m_pPopupMenu->SetVisibleAction( eDelete, false );
		}

		m_pPopupMenu->exec( QCursor::pos() );

	} else if ( a_pEvent->button() == Qt::LeftButton ) {
		setDown( true );
		emit pressed();
		update();
	}
}

void mkHotkeyButton::OnPaint( QPainter *a_pPainter )
{
	if ( !a_pPainter )
		return ;
	
	if ( !m_strName.isEmpty() ) {
		QFont trebuchetFont( QFont( MONKEY_FONT, 7 ));
		trebuchetFont.setCapitalization( QFont::MixedCase );
		a_pPainter->setFont( trebuchetFont );
		a_pPainter->setRenderHint( QPainter::TextAntialiasing );

		if ( isDown() ) a_pPainter->setPen( Qt::black );
		else a_pPainter->setPen( Qt::white );

		QFontMetrics fontMetrics( trebuchetFont );
		a_pPainter->drawText( QRect( 3, 0, 64, 20 ), Qt::AlignHCenter,
                         				fontMetrics.elidedText( m_strName, Qt::ElideRight, 65 ));
	}
	
	if ( !m_strKeyInfo.isEmpty() ) {
		QFont trebuchetFont( QFont( MONKEY_FONT, 7 ));
		trebuchetFont.setCapitalization( QFont::Capitalize );
		a_pPainter->setFont( trebuchetFont );
		a_pPainter->setRenderHint( QPainter::TextAntialiasing );

		if ( isDown() ) a_pPainter->setPen( Qt::black );
		else a_pPainter->setPen( Qt::white );

		QFontMetrics fontMetrics( trebuchetFont );
		a_pPainter->drawText( QRect( 5, 52, 60, 20 ), Qt::AlignHCenter,
				                         fontMetrics.elidedText( m_strKeyInfo, Qt::ElideRight, 60 ));			
	}
}

void mkHotkeyButton::OnEnter( QEvent *a_pPainter )
{
	if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() ))
		m_pEnterTimer->start( 300 );
}

void mkHotkeyButton::OnLeave( QEvent *a_pPainter )
{
	if ( m_pEnterTimer->isActive() )
		m_pEnterTimer->stop();

	m_pConfigButton->setVisible( false );
	m_pDeleteButton->setVisible( false );
}

void mkHotkeyButton::SlotEnterTimer()
{
	m_pConfigButton->setVisible( true );
	m_pDeleteButton->setVisible( true );

	m_pEnterTimer->stop();
}

void mkHotkeyButton::dragEnterEvent( IN QDragEnterEvent *a_pEvent )
{
	QEvent event( QEvent::Enter );
	enterEvent( &event );

	a_pEvent->acceptProposedAction();
}

void mkHotkeyButton::dragLeaveEvent( IN QDragLeaveEvent *a_pEvent )
{
	QEvent event( QEvent::Leave );
	leaveEvent( &event );
}

void mkHotkeyButton::dropEvent( IN QDropEvent *a_pEvent )
{
	const QMimeData *pMimeData = a_pEvent->mimeData();

	if ( pMimeData->hasUrls() ) {
        QList<QUrl> urlList = pMimeData->urls();

        if ( urlList.size() == 1 ) {
        	QString strFileName = urlList.at( 0 ).path();

			if ( strFileName.at( 0 ) == '/' )
				strFileName.remove( 0, 1 );

        	/* return, if drop item is directory. */
        	QFileInfo fileInfo( strFileName );
        	if ( fileInfo.isDir() )
        		return ;

        	if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() ))
    			SlotDeleteClicked();

    		m_strName = GetIconName( strFileName );
    		m_strFilePath = strFileName;

    		m_hotkeyIcon = GetIcon( strFileName );
    		EnableIcon( false );

    		setToolTip( m_strName );
    		update();

    		QEvent event( QEvent::Enter );
    		enterEvent( &event );
        }
	}

	a_pEvent->acceptProposedAction();
}

void mkHotkeyButton::SlotClicked()
{
	if ( !m_strFilePath.isEmpty() ) {
		static_cast<mkMainDialog*>( parent()->parent() )->Execute( m_strFilePath );
	} else {
		SlotFileOpenClicked();
	}
}

void mkHotkeyButton::SlotFileOpenClicked()
{
	QString strFileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString("C:/"), tr("All Files (*)"));
	if (!strFileName.isEmpty()) {
		
		if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() ))
			SlotDeleteClicked();
		
		m_strName = GetIconName( strFileName );	// strFileName include absolute full-path
		m_strFilePath = strFileName;

		m_hotkeyIcon = GetIcon( strFileName );
		EnableIcon( false );
			
		setToolTip( m_strName );
		update();
	}
}

void mkHotkeyButton::SlotURLClicked()
{
	QString strCurrentUrl;

	if ( m_strFilePath.contains( "http://", Qt::CaseInsensitive ))
		strCurrentUrl = m_strFilePath;

	QString strUrl = static_cast<mkMainDialog *>( parent()->parent() )->ShowURLDialog( strCurrentUrl );

	if ( strUrl.isEmpty() || strUrl == m_strFilePath )
		return ;

	if (( !m_strName.isEmpty() && !m_hotkeyIcon.isNull() ))
		SlotDeleteClicked();

	m_strName = "Loading...";

	MK_DELETE( m_pHttpFavicon );
	m_pHttpFavicon = new mkHttpDownloader( this );
	m_pHttpFavicon->SetUrl( strUrl );
	m_pHttpFavicon->Connect();
}

void mkHotkeyButton::SlotConfigClicked()
{
 	emit SigShowKeyboard( m_nIndex );
	setDown( false ); 
}

void mkHotkeyButton::SlotDeleteClicked()
{
	m_nSystemKey = -1;
	m_nNonSystemKey = -1;

	m_strName = "";
	m_strKeyInfo = "";
	m_strFilePath = "";
	
	setToolTip( "" );

	QImage nullImage;
	SetFGImage( nullImage, nullImage, nullImage );
	m_hotkeyIcon = QIcon();

	SetAnimation( false );
	
	mkHotkeyManager::Instance()->RemoveHotkeyAt( m_nIndex );
	
	/* 삭제 버튼을 press 상태로 유지된채 부모 버튼이 click 포커스를 가지면
	     삭제 버튼을 눌러도 부모 버튼의 포커스가 사라지지 않는 현상 */
	setDown( false );

	m_pConfigButton->setVisible( false );
	m_pDeleteButton->setVisible( false );

	update();
}
